function buildStats(home, away, firstPeriod, secondPeriod) {
    stats = {
        home: {
        },
        away: {
        }
    };
    function blankStat() {
        return {
            jamDuration : 0,
            jamCount : 0,
            points: 0,
            oppPoints: 0,
            lead: 0,
            oppLead: 0,
            lost: 0,
            oppLost: 0,
            noPass: 0,
            oppNoPass: 0,
            call: 0,
            oppCall: 0,
            minors: 0,
            majors: 0,
            explusions: 0,
            minorPenalties: [],
            majorPenalties: [],
            expulsionPenalties: [],
            actionsErrors: {}
        };
    }
    function blankStats() {
        return {
            "jammer" : blankStat(),
            "pivot" : blankStat(),
            "blocker" : blankStat(),
            "blocker_pivot" : blankStat(),
            "blocker_pivot_jammer" : blankStat(),
        };
    };
    // build entries for teams
    $(home).find("person").each(function (index, person) {
        stats.home[$(person).attr("number")] = blankStats();
    });
    $(away).find("person").each(function (index, person) {
        stats.away[$(person).attr("number")] = blankStats();
    });
    $([firstPeriod, secondPeriod]).find("jam").each(function (index, jam) {
        var jamDuration = JamDuration(jam);
        var homePts = JamPoints(jam, home);
        var awayPts = JamPoints(jam, away);
        var homeLead = JamLead(jam, home);
        var awayLead = JamLead(jam, away);
        var homeLost = JamLost(jam, home);
        var awayLost = JamLost(jam, away);
        var homeCall = JamCalled(jam, home);
        var awayCall = JamCalled(jam, away);
        function addJamPositionStats(stats, team) {
            stats.jamDuration += jamDuration;
            stats.jamCount += 1;
            if (team == home) {
                stats.points += homePts;
                stats.oppPoints += awayPts;
                stats.lead += homeLead;
                stats.oppLead += awayLead;
                stats.lost += homeLost;
                stats.oppLost += awayLost;
                stats.call += homeCall;
                stats.oppCall += awayCall;
            } else {
                stats.points += awayPts;
                stats.oppPoints += homePts;
                stats.lead += awayLead;
                stats.oppLead += homeLead;
                stats.lost += awayLost;
                stats.oppLost += homeLost;
                stats.call += awayCall;
                stats.oppCall += homeCall;
            }
        }
        function addJamStats(stats, position, team, fn) {
            if (position == "jammer") {
                fn(stats["jammer"], team);
                fn(stats["blocker_pivot_jammer"], team);
            } else if (position == "pivot") {
                fn(stats["pivot"], team);
                fn(stats["blocker_pivot"], team);
                fn(stats["blocker_pivot_jammer"], team);
            } else if (position == "blocker") {
                fn(stats["blocker"], team);
                fn(stats["blocker_pivot"], team);
                fn(stats["blocker_pivot_jammer"], team);
            }
        }
        $(jam).find("lineup").each(function (index, lineup) {
            var skaterNum = $(lineup).attr("skater");
            if (skaterNum == "???" || skaterNum == "?")
                return;
            var position = $(lineup).attr("position");
            if (EventIsTeam(lineup, home)) {
                addJamStats(stats.home[skaterNum], position, home, addJamPositionStats);
            } else if (EventIsTeam(lineup, away)) {
                addJamStats(stats.away[skaterNum], position, away, addJamPositionStats);
            }
            // add the penaties in the current jam
            $(jam).find("penalty").each(function (index, penalty) {
                var pSkaterNum = $(penalty).attr("skater");
                if (pSkaterNum != skaterNum) {
                    return;
                }
                var severity = $(penalty).attr("severity");
                if (!severity) {
                    severity = "major";
                }
                if (EventIsTeam(penalty, home)) {
                    addJamStats(stats.home[skaterNum], position, home, 
                        function(stats, team) { 
                            stats[severity+"s"] += 1;
                            stats[severity+"Penalties"].push({
                                jam:$(jam).attr('number'),
                                position: position,
                                penalty:$(penalty).attr('penalty')
                            }); 
                        }
                    );
                } else if (EventIsTeam(penalty, away)) {
                    addJamStats(stats.away[skaterNum], position, away, 
                        function(stats, team) { 
                            stats[severity+"s"] += 1;
                            stats[severity+"Penalties"].push({
                                jam:$(jam).attr('number'),
                                position: position,
                                penalty:$(penalty).attr('penalty')
                            });
                         }
                     );
                }
            });
       });
    });
    // now find the team averages
    function findAverages(team) {
        var average = blankStats();
        $.each(team,function (skaterNum, skater) {
            $.each(average,function (position, stat) {
                if (!stat.count) {
                    stat.count = 1;
                } else {
                    stat.count += 1;
                }
                $.each(stat, function (index, value) {
                    if (skater[position][index]) {
                       stat[index] += skater[position][index];
                   }
               });
            });
        });
        $.each(average, function (position, stat) {
            if (stat.count) {
                 $.each(stat, function (index, value) {
                    stat[index] /= stat.count;
                });
                var vtar = (stat.points - stat.oppPoints) / stat.jamCount;
                $.each(team,function (skaterNum, skater) {
                    skater[position].teamPosvtar = vtar;
                });
            }
        });
        team.average = average;
    }
    findAverages(stats.home);
    findAverages(stats.away);
    // actions and errors are currently per period - add support for per jam?
    function addActionError(index, action) {
        var stat = null;
        var skaterNum = $(action).attr("skater");
        if (EventIsTeam(action, home)) {
            stat = stats.home[skaterNum]["blocker_pivot_jammer"];
        } else if (EventIsTeam(action, away)) {
            stat = stats.away[skaterNum]["blocker_pivot_jammer"];
        }
        var count = $(action).attr("count");
        if (!count) { // count is optional
            count = 1;
        } else {
            count = Number(count);
        }
        var desc = $(action).text();
        if (stat.actionsErrors[desc]) {
            stat.actionsErrors[desc] += count;
        } else {
            stat.actionsErrors[desc] = count;
        }
    }
    $([firstPeriod, secondPeriod]).find("action").each(addActionError);
    $([firstPeriod, secondPeriod]).find("error").each(addActionError);
    // and copy over
    $(["jammer","pivot","blocker","blocker_pivot"]).each(function (index, position) {
        $.each(stats.home,function (skaterNum, skater) {
            stats.home[skaterNum][position].actionsErrors = stats.home[skaterNum]["blocker_pivot_jammer"].actionsErrors;
        });
        $.each(stats.away,function (skaterNum, skater) {
            stats.away[skaterNum][position].actionsErrors = stats.away[skaterNum]["blocker_pivot_jammer"].actionsErrors;
        });
    });
    return stats;
}